package cn.pconline.autoclub.service;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.gelivable.dao.GeliDao;
import org.gelivable.dao.GeliOrm;
import org.gelivable.dao.SqlBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;

public class BaseService {
    private static final Logger log = LoggerFactory.getLogger(BaseService.class);
    
    @Autowired
    private GeliDao geliDao;
    @Autowired
    private GeliOrm geliOrm;
    
    public <T> T findUniqueLongKeyObject(Class<T> type, String sql, Object... params) {
        StringBuilder cacheKey = new StringBuilder(type.getSimpleName());
        cacheKey.append("-id");
        if(params != null) {
            for(Object param : params) {
                cacheKey.append('-');
                cacheKey.append(param);
            }
        }
        Object id = geliDao.getCache(cacheKey.toString());
        if(id == null) {
            try {
                log.info("get id from db: {}, {}", sql, Arrays.toString(params));
                id = geliDao.getJdbcTemplate().queryForObject(sql, GeliDao.longIdRowMapper, params);
            } catch (EmptyResultDataAccessException e) {
                log.info("not record: {}, {}", sql, Arrays.toString(params));
                return null;
            }
        }
        if(id == null) {
            return null;
        }
        try {
            log.info("find object[{}: {}]", cacheKey,id);
            T t = geliDao.find(type, id);
            if(t != null) {
                geliDao.setCache(cacheKey.toString(), id);
            }
            return t;
        } catch (EmptyResultDataAccessException e) {
            log.info("not record: {}, {}", type.getSimpleName(), id);
            geliDao.deleteCache(cacheKey.toString());
            return null;
        }
    }
    public <T> T findUniqueLongKeyObject(Class<T> type, long x, Map<String, Object> params) {
        return findUniqueLongKeyObject(type, x, params, false);
    }
    
    /**
     * @param type 实体类
     * @param params 参数，key:表字段，value：条件值
     * @return
     */
    public <T> T findUniqueLongKeyObject(Class<T> type, Map<String, Object> params) {
        return findUniqueLongKeyObject(type, 0, params, false);
    }
    
    /**
     * @param type 实体类
     * @param params 参数，key:表字段，value：条件值
     * @param flushCache true/false 是否要刷新唯一约束id缓存
     * @return
     */
    public <T> T findUniqueLongKeyObject(Class<T> type, Map<String, Object> params, boolean flushCache) {
        return findUniqueLongKeyObject(type, 0, params, flushCache);
    }
    /**
     * 
     * @param type 实体类
     * @param x 分表字段值，0时表示没有分表
     * @param params 参数，key:表字段，value：条件值
     * @param flushCache true/false 是否要刷新唯一约束id缓存
     * @return
     */
    public <T> T findUniqueLongKeyObject(Class<T> type, long x, Map<String, Object> params, boolean flushCache) {
        StringBuilder cacheKey = new StringBuilder(type.getSimpleName());
        cacheKey.append("-id");
        SqlBuilder sql = new SqlBuilder();
        String table = geliOrm.getTableName(type);
        if(x > 0) {
            table = geliOrm.getTableName(type, x);
        }
        sql.appendSql("select ").appendSql(geliOrm.getKeyColumn(type)).appendSql(" from ").appendSql(table);
        if(params != null) {
            sql.appendSql(" where 1 = 1 ");
            Iterator<Entry<String, Object>> iter = params.entrySet().iterator();
            while(iter.hasNext()) {
                Entry<String, Object> fv = iter.next();
                String column = fv.getKey();
                Object value = fv.getValue();
                cacheKey.append('-');
                cacheKey.append(column);
                cacheKey.append('-');
                cacheKey.append(value);
                
                sql.appendSql(" and ").appendSql(column).appendSql(" = ").appendValue(value);
            }
        }
        sql.appendSql(" limit 0, 1");
        Object id = null;
        if(!flushCache) {
            id = geliDao.getCache(cacheKey.toString());
        } else {
            geliDao.deleteCache(cacheKey.toString());
        }
        if(id == null) {
            try {
                log.info("get id from db: {}, {}", sql.getSql(), Arrays.toString(sql.getValues()));
                id = geliDao.getJdbcTemplate().queryForObject(sql.getSql(), GeliDao.longIdRowMapper, sql.getValues());
            } catch (EmptyResultDataAccessException e) {
                log.info("not record: {}, {}", sql.getSql(), Arrays.toString(sql.getValues()));
                return null;
            }
        }
        if(id == null) {
            return null;
        }
        if(flushCache) {
            geliDao.deleteCache(type, id);
        }
        try {
            log.info("find object[{}: {}]", cacheKey,id);
            T t = null;
            if(x > 0) {
                t = geliDao.find(type, x, id);
            } else {
                t = geliDao.find(type, id);
            }
            if(t != null) {
                geliDao.setCache(cacheKey.toString(), id);
            }
            return t;
        } catch (EmptyResultDataAccessException e) {
            log.info("not record: {}, {}", type.getSimpleName(), id);
            geliDao.deleteCache(cacheKey.toString());
            return null;
        }
    }
    
    /**
     * 获取唯一约束对象缓存id
     * @param type 实体类
     * @param params 参数，key:表字段，value：条件值
     * @return 对象id
     */
    public <T> Object getUniqueObjectCacheId(Class<T> type, Map<String, Object> params) {
        StringBuilder cacheKey = new StringBuilder(type.getSimpleName());
        cacheKey.append("-id");
        if(params != null) {
            Iterator<Entry<String, Object>> iter = params.entrySet().iterator();
            while(iter.hasNext()) {
                Entry<String, Object> fv = iter.next();
                String column = fv.getKey();
                Object value = fv.getValue();
                cacheKey.append('-');
                cacheKey.append(column);
                cacheKey.append('-');
                cacheKey.append(value);
            }
        }
        return geliDao.getCache(cacheKey.toString());
    }
    
    /**
     * <b>注：</b>如果返回false，这时db数据的id并不是实体的id,<br/>
     * 更新指定字段后mc不会自动清，在返回false时使用处理清下mc
     * 
     * @param entity 带主键值实体
     * @param updateParams 重复时更新的字段，key:表字段，value：更新值
     * @return true：新增，false：更新
     */
    public boolean createDuplicateUpdate(Object entity, Map<String, Object> updateParams) {
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append(geliOrm.getCreateSql(entity));
        Map<String, Object> params = geliOrm.map(entity);
        if(updateParams != null) {
            sqlBuilder.append(" ON DUPLICATE KEY UPDATE ");
            Iterator<Entry<String, Object>> iter = updateParams.entrySet().iterator();
            StringBuilder updateSql = new StringBuilder();
            while(iter.hasNext()) {
                Entry<String, Object> fv = iter.next();
                String column = fv.getKey();
                String key = column + "_1";
                Object value = fv.getValue();
                updateSql.append(",").append(column).append("=:").append(key);
                params.put(key, value);
            }
            sqlBuilder.append(updateSql.substring(1));
        }
        String sql = sqlBuilder.toString();
        log.info("createDuplicateUpdate sql: {}, params: {}", sql, params);
        int cnt = geliDao.getNamedParameterJdbcTemplate().update(sql, params);
        return cnt == 1;
    }

    /**
     * <b>注：</b>如果返回false，这时db数据的id并不是实体的id
     * @param entity 带主键值实体
     * @return true：新增，false：存在忽略
     */
    public boolean createDuplicateIgnore(Object entity) {
        String sql = geliOrm.getCreateSql(entity);
        String orgTbl = geliOrm.getTableName(entity.getClass());
        sql = sql.replace(sql.substring(0, sql.indexOf(orgTbl)), "insert ignore into ");
        Map<String, Object> params = geliOrm.map(entity);
        log.info("createDuplicateIgnore sql: {}, params: {}", sql, params);
        int cnt = geliDao.getNamedParameterJdbcTemplate().update(sql, params);
        return cnt == 1;
    }
}
